package com.cnbot.camera.utils;

/**
 * Copyright (c) 2016--2019/3/25  Hunan Cnbot Co., Ltd. All Rights Reserved.
 *
 * @descriptoin 摄像头数据处理类
 * @FileName: JavaFilter.java
 * @author: wzz
 * @date: 2019/3/25 15:40
 * @version: 1.0
 */

public class JavaFilter {

    private static final int[] G_V_TABLE = new int[256];
    private static final int[] G_U_TABLE = new int[256];
    private static final int[] Y_TABLE = new int[256];
    private static final int[] R_YV_TABLE = new int[65536];
    private static final int[] B_YU_TABLE = new int[65536];

    private static final int  BYTEMAXLEN = 256;

    static {
        initTable();
    }

    private static void initTable() {
        int m = 0, n = 0;
        for (m = 0; m < BYTEMAXLEN; m++) {
            G_V_TABLE[m] = 833 * (m - 128);
            G_U_TABLE[m] = 400 * (m - 128);
            Y_TABLE[m] = 1192 * (m - 16);
        }
        int temp = 0;
        for (m = 0; m < BYTEMAXLEN; m++) {
            for (n = 0; n < BYTEMAXLEN; n++) {
                temp = 1192 * (m - 16) + 1634 * (n - 128);
                R_YV_TABLE[m * 256 + n] = temp < 0 ? 0 : temp > 262143 ? 262143 : temp;
                temp = 1192 * (m - 16) + 2066 * (n - 128);
                B_YU_TABLE[m * 256 + n] = temp < 0 ? 0 : temp > 262143 ? 262143 : temp;
            }
        }
    }

    /**
     * byte[] YUV420SP→int[] ARGB変換
     */
    static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
        final int frameSize = width * height;

//        int pSize = width * height;

        for (int j = 0, yp = 0; j < height; j++) {
            int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
            for (int i = 0; i < width; i++, yp++) {
                int y = (0xff & ((int) yuv420sp[yp])) - 16;
                if (y < 0) {
                    y = 0;
                }
                if ((i & 1) == 0) {
                    v = (0xff & yuv420sp[uvp++]) - 128;
                    u = (0xff & yuv420sp[uvp++]) - 128;
                }

                int y1192 = 1192 * y;
                int r = (y1192 + 1634 * v);
                int g = (y1192 - 833 * v - 400 * u);
                int b = (y1192 + 2066 * u);

                if (r < 0) {
                    r = 0;
                } else if (r > 262143) {
                    r = 262143;
                }
                if (g < 0) {
                    g = 0;
                } else if (g > 262143) {
                    g = 262143;
                }
                if (b < 0) {
                    b = 0;
                } else if (b > 262143) {
                    b = 262143;
                }
                //镜像
                rgb[2 * j * width + width - yp - 1] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
                //不镜像
                //rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
            }
        }
    }

    static public void decodeYUV420SPTable(int[] rgb, byte[] yuv420sp, int width, int height, int imgSize) {
        int size = 2;
        int y0, y1;
        int u = 0;
        int v = 0;
        int r;
        int g;
        int b;

        int yoff0 = 0;
        int yoff1 = 0;
        int uoff = imgSize;

        int i = 0;
        int j = 0;
        int mirrorPos = 0;

        int yPos = 0;

        for (j = 0; j < height; j += size) {
            for (i = 0; i < width; i++, yoff0++) {

                y0 = (0xff & ((int) yuv420sp[yoff0]));
                y0 = y0 < 0 ? 0 : y0;

                yoff1 = yoff0 + width;
                y1 = (0xff & ((int) yuv420sp[yoff1]));
                y1 = y1 < 0 ? 0 : y1;

                //偶数列取位置，奇数列用上一个循环的位置
                if ((i & 1) == 0) {
                    v = (0xff & yuv420sp[uoff++]);
                    u = (0xff & yuv420sp[uoff++]);
                }

                yPos = y0 << 8;
                r = R_YV_TABLE[yPos | v];
                g = (Y_TABLE[y0] - G_V_TABLE[v] - G_U_TABLE[u]);
                b = B_YU_TABLE[yPos | u];

                g = g < 0 ? 0 : g > 262143 ? 262143 : g;

                mirrorPos = width - (i << 1) - 1;

                rgb[yoff0 + mirrorPos] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

                yPos = y1 << 8;
                r = R_YV_TABLE[yPos | v];
                g = (Y_TABLE[y1] - G_V_TABLE[v] - G_U_TABLE[u]);
                b = B_YU_TABLE[yPos | u];

                g = g < 0 ? 0 : g > 262143 ? 262143 : g;

                rgb[yoff1 + mirrorPos] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
            }
            yoff0 += width;
        }
    }

    public static byte[] rgb2YCbCr420(int[] pixels, int width, int height) {
        int len = width * height;
        // yuv格式数组大小，y亮度占len长度，u,v各占len/4长度。
        byte[] yuv = new byte[len * 3 / 2];
        int y, u, v;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                // 屏蔽ARGB的透明度值
                int rgb = pixels[i * width + j] & 0x00FFFFFF;
                // 像素的颜色顺序为bgr，移位运算。
                int r = rgb & 0xFF;
                int g = (rgb >> 8) & 0xFF;
                int b = (rgb >> 16) & 0xFF;
                // 套用公式
                y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
                u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
                v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
                // rgb2yuv
                // y = (int) (0.299 * r + 0.587 * g + 0.114 * b);
                // u = (int) (-0.147 * r - 0.289 * g + 0.437 * b);
                // v = (int) (0.615 * r - 0.515 * g - 0.1 * b);
                // RGB转换YCbCr
                // y = (int) (0.299 * r + 0.587 * g + 0.114 * b);
                // u = (int) (-0.1687 * r - 0.3313 * g + 0.5 * b + 128);
                // if (u > 255)
                // u = 255;
                // v = (int) (0.5 * r - 0.4187 * g - 0.0813 * b + 128);
                // if (v > 255)
                // v = 255;
                // 调整
                y = y < 16 ? 16 : (y > 255 ? 255 : y);
                u = u < 0 ? 0 : (u > 255 ? 255 : u);
                v = v < 0 ? 0 : (v > 255 ? 255 : v);
                // 赋值
                yuv[i * width + j] = (byte) y;
                yuv[len + (i >> 1) * width + (j & ~1) + 0] = (byte) u;
                yuv[len + +(i >> 1) * width + (j & ~1) + 1] = (byte) v;
            }
        }
        return yuv;
    }

//    /**
//     * 获取位图的YUV数据
//     */
//
//    public static byte[] getYUVByBitmap(Bitmap bitmap) {
//        if (bitmap == null) {
//            return null;
//        }
//        int width = bitmap.getWidth();
//        int height = bitmap.getHeight();
//        int size = width * height;
//        int pixels[] = new int[size];
//        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
//        // byte[] data = convertColorToByte(pixels);
//        byte[] data = rgb2YCbCr420(pixels, width, height);
//        return data;
//    }

    public static void decodeYUV420SP(int[] rgb, byte[] nv21, int width, int height, int frameSize) {
        int y, cb = 0, cr = 0, index = 0;
        int r, g, b;
        int indexWidth = 0;
        int halfIndexWidth = 0;

        long sTime = System.currentTimeMillis();
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                y = nv21[indexWidth + j];
                if (y < 0) {
                    y += 255;
                }

                if ((j & 1) == 0) {
                    //V
                    cr = nv21[halfIndexWidth + j + frameSize];
                    //U
                    cb = nv21[halfIndexWidth + j + frameSize + 1];

                    cb = (cb < 0) ? (cb + 127) : (cb - 128);
                    cr = (cr < 0) ? (cr + 127) : (cr - 128);
                }

                r = y + cr + (cr >> 2) + (cr >> 3) + (cr >> 5);
                g = y - (cb >> 2) + (cb >> 4) + (cb >> 5) - (cr >> 1) + (cr >> 3) + (cr >> 4) + (cr >> 5);
                b = y + cb + (cb >> 1) + (cb >> 2) + (cb >> 6);

                r = (r < 0) ? 0 : (r > 255) ? 255 : r;
                g = (g < 0) ? 0 : (g > 255) ? 255 : g;
                b = (b < 0) ? 0 : (b > 255) ? 255 : b;

                rgb[index++] = 0xff000000 + (r << 16) + (g << 8) + b;
            }
            indexWidth += width;
            if ((i & 1) == 1) {
                halfIndexWidth += width;
            }

//            Log.d("JavaFilter", "decodeYUV420SPwTime: " + (System.nanoTime() - s1Time));
        }
        //Log.d("JavaFilter", "decodeYUV420SP: " + (System.currentTimeMillis() - sTime));

    }
}
